﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Permissions;
using System.IO;
using Microsoft.Win32;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Xml;
using Toub.MediaCenter.Dvrms.Metadata;
using System.Collections;

namespace Convert_DVR_MS_to_iTunes
{
    public partial class frmMain : Form
    {
        #region Module Level Variables

        private enum Convertor
        {
            MCEBuddy = 1,
            HandbrakeCLI = 2,
            DVRMSToolbox = 3
        }
        private Convertor m_convertor = Convertor.HandbrakeCLI;

        private bool m_errorsOccurred = false;

        private string m_Output;

        bool m_ignoreNextEvent = false;
        string m_source = "";
        string m_destination = "";
        private HandbrakeOptions m_handbrakeOptions = new HandbrakeOptions();

        FilesForProcessing m_filesForProcessing = new FilesForProcessing();

        Process m_process;

        #endregion

        #region Form

        // Force UAC to elevate your securitygrade
        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        public frmMain(string sourceFolder, string destinationFolder)
        {
            InitializeComponent();

            m_source = sourceFolder;
            m_destination = destinationFolder;

            m_handbrakeOptions.SettingsString = Properties.Settings.Default.HandbrakeOptions;
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            m_ignoreNextEvent = true;
            txtSource.Text = m_source;
            txtDestination.Text = m_destination;
            m_ignoreNextEvent = false;

            cboConverter.Items.Add("MCE Buddy");
            cboConverter.Items.Add("Handbrake CLI");
            cboConverter.Items.Add("DVRMS Toolbox");
            cboConverter.SelectedItem = "Handbrake CLI";

            PopulateParsley();

            ResizeDescriptionArea(ref grdOptions, 3);
        }

        private void frmMain_Shown(object sender, EventArgs e)
        {
            txtSourceFolder_TextChanged(null, null);
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (m_process != null)
            {
                m_process.ErrorDataReceived -= new DataReceivedEventHandler(process_ErrorDataReceived);
                m_process.OutputDataReceived -= new DataReceivedEventHandler(process_OutputDataReceived);

                m_process.Kill();
                m_process.Close();
                m_process = null;
            }
            Properties.Settings.Default.HandbrakeOptions = m_handbrakeOptions.SettingsString;
            Properties.Settings.Default.Save();
        }

        #endregion

        #region UI Events

        private void txtSourceFolder_TextChanged(object sender, EventArgs e)
        {
            if (m_ignoreNextEvent) return;

            m_source = txtSource.Text;
            grdFiles.RowCount = 0;

            // Populate filelist
            getCurrentFileList();
            grdFiles.RowCount = m_filesForProcessing.Count;

            for (int i = 0; i < m_filesForProcessing.Count; i++)
            {
                FileInfo fi = new FileInfo(m_filesForProcessing.Item(i).SourcePathFile);
                grdFiles.Rows[i].Cells[0].Value = Properties.Resources.unknown;
                grdFiles.Rows[i].Cells[1].Value = fi.Name;
            }
        }

        private void txtDestinationFolder_TextChanged(object sender, EventArgs e)
        {
            m_destination = txtDestination.Text;
        }

        private void cmdSourceFolder_Click(object sender, EventArgs e)
        {
            uiFolderBrowse.SelectedPath = txtSource.Text;
            uiFolderBrowse.ShowDialog(this);
            txtSource.Text = uiFolderBrowse.SelectedPath;
        }

        private void cmdDestinationFolder_Click(object sender, EventArgs e)
        {
            uiFolderBrowse.SelectedPath = txtDestination.Text;
            uiFolderBrowse.ShowDialog(this);
            txtDestination.Text = uiFolderBrowse.SelectedPath;
        }

        private void cmdSourceFile_Click(object sender, EventArgs e)
        {
            uiFileOpen.InitialDirectory = txtSource.Text;
            uiFileOpen.ShowDialog(this);
            txtSource.Text = uiFileOpen.FileName;
        }

        private void cmdDestinationFile_Click(object sender, EventArgs e)
        {
            uiFileOpen.InitialDirectory = txtDestination.Text;
            uiFileOpen.ShowDialog(this);
            txtDestination.Text = uiFileOpen.FileName;
        }

        private void cboConvertUsing_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (((ComboBox)sender).SelectedItem.ToString())
            {
                case "MCE Buddy":
                    m_convertor = Convertor.MCEBuddy;
                    m_handbrakeOptions.ConvertorPath = "";
                    break;
                case "Handbrake CLI":
                    m_convertor = Convertor.HandbrakeCLI;
                    try
                    {
                        string handbrake = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Handbrake.exe", "", "").ToString();
                        FileInfo fi = new FileInfo(handbrake);
                        m_handbrakeOptions.ConvertorPath = Path.Combine(fi.DirectoryName, "HandbrakeCLI.exe");
                    }
                    catch
                    {
                        m_handbrakeOptions.ConvertorPath = "";
                    }
                    break;
                case "DVRMS Toolbox":
                    m_convertor = Convertor.DVRMSToolbox;
                    m_handbrakeOptions.ConvertorPath = "";
                    break;
            }

            SetOptionStates();
            SetButtonStates();
        }

        private void cmdOK_Click(object sender, EventArgs e)
        {
            getCurrentFileList();
            processFiles();
        }

        private void cmdCancel_Click(object sender, EventArgs e)
        {
            m_handbrakeOptions.SearchForParsley -= new HandbrakeOptions.SearchForParsleyEventHandler(SearchForParsley);
            this.Close();
        }

        private void grdFiles_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (m_filesForProcessing.Item(e.RowIndex).MessageLog == null)
                MessageBox.Show("No messages to show for this file.",
                    "Messages", MessageBoxButtons.OK, MessageBoxIcon.Information);
            else
                MessageBox.Show(m_filesForProcessing.Item(e.RowIndex).MessageLog.ToString(),
                    "Messages", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        #endregion

        #region General Methods

        private bool SourceIsAFile()
        {
            FileInfo fi = new FileInfo(m_source);
            return (fi.Exists);
        }

        private bool ResizeDescriptionArea(ref PropertyGrid grid, int nNumLines)
        {
            try
            {
                System.Reflection.PropertyInfo pi = grid.GetType().GetProperty("Controls");
                System.Windows.Forms.Control.ControlCollection cc = (System.Windows.Forms.Control.ControlCollection)pi.GetValue(grid, null);

                foreach (Control c in cc)
                {
                    Type ct = c.GetType();
                    string sName = ct.Name;

                    if (sName == "DocComment")
                    {
                        pi = ct.GetProperty("Lines");
                        pi.SetValue(c, nNumLines, null);

                        System.Reflection.FieldInfo fi = ct.BaseType.GetField("userSized",
                            System.Reflection.BindingFlags.Instance |
                            System.Reflection.BindingFlags.NonPublic);

                        fi.SetValue(c, true);
                    }
                }

                return true;
            }
            catch (Exception error)
            {
#if(DEBUG)
                MessageBox.Show(error.Message, "ResizeDescriptionArea()");
#endif

                return false;
            }
        }
 
        private static string ReadDVRMSMetadata(string pathFile, string metaDataAttributeName)
        {
            DvrmsMetadataEditor dvrmsFile = new DvrmsMetadataEditor(pathFile);

            IDictionary dvrmsMetadata = dvrmsFile.GetAttributes();

            return ((MetadataItem)dvrmsMetadata[metaDataAttributeName]).Value.ToString();
        }

        private void PopulateParsley()
        {
            string[] files = Properties.Settings.Default.ParsleyPath.Split(',');

            m_handbrakeOptions.ParsleyPaths.Clear();

            m_handbrakeOptions.ParsleyPaths.Add("(Search All Drives)");
            string[] drives = System.Environment.GetLogicalDrives();

            foreach (string dr in drives)
            {
                DriveInfo di = new DriveInfo(dr);

                // Here we skip the drive if it is not ready to be read.
                if (di.IsReady && di.DriveType == DriveType.Fixed)
                {
                    m_handbrakeOptions.ParsleyPaths.Add("(Search " + di.VolumeLabel + " (" + di.RootDirectory.ToString().Replace("\\", "") + "))");
                }
            }

            foreach (string file in files)
            {
                if (File.Exists(file))
                {
                    m_handbrakeOptions.ParsleyPaths.Add(file);
                }
            }
        }

        private void SetOptionStates()
        {
            m_handbrakeOptions.SearchForParsley -= new HandbrakeOptions.SearchForParsleyEventHandler(SearchForParsley);

            switch (m_convertor)
            {
                case Convertor.MCEBuddy:
                    grdOptions.SelectedObject = null;
                    break;
                case Convertor.HandbrakeCLI:
                    grdOptions.SelectedObject = m_handbrakeOptions;
                    m_handbrakeOptions.SearchForParsley += new HandbrakeOptions.SearchForParsleyEventHandler(SearchForParsley);
                    break;
                case Convertor.DVRMSToolbox:
                    grdOptions.SelectedObject = null;
                    break;
            }
        }

        private void SearchForParsley(object source, EventArgs e, string value)
        {
            FileHelper fileHlp = new FileHelper();
            List<string> files;

            if (value == "(Search All Drives)")
            {
                files = fileHlp.FileFind("AtomicParsley.exe", true, staMain, toolstripProgress);
            }
            else
            {
                string drive = value.Substring(value.LastIndexOf('(') + 1, 2) + "\\";
                files = fileHlp.FileFind(drive, "AtomicParsley.exe", true, staMain, toolstripProgress);
            }

            string pathList = "";

            if (files != null)
            {
                foreach (string file in files)
                {
                    if (pathList != "") pathList += ",";
                    pathList += file;
                }
            }

            // TODO:DS Save a selected ParsleyPath
            Properties.Settings.Default.ParsleyPath = pathList;
            Properties.Settings.Default.Save();

            PopulateParsley();
        }

        private void SetButtonStates()
        {
            cmdOK.Enabled = (File.Exists(m_handbrakeOptions.ConvertorPath));
        }

        #endregion

        #region File Handling

        private bool IsFileLocked(string fileName)
        {
            FileStream fs;
            bool IsFileLocked = false;

            try
            {
                fs = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None);
                fs.Close();
            }
            catch (IOException e)
            {
                int errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
                IsFileLocked = (errorCode == 32 || errorCode == 33);

                if (!IsFileLocked) throw;
            }

            return IsFileLocked;
        }

        private void getCurrentFileList()
        {
            FileForProcessing file;
            m_filesForProcessing.Clear();

            if (m_convertor == Convertor.MCEBuddy)
            {
                foreach (string f in Directory.GetFiles(m_source, "*.dvr-ms", SearchOption.TopDirectoryOnly))
                {
                    file = new FileForProcessing();
                    file.SourcePathFile = f;
                    m_filesForProcessing.Add(file);
                }
            }

            if (m_convertor == Convertor.HandbrakeCLI)
            {
                if (SourceIsAFile())
                {
                    file = new FileForProcessing();
                    file.SourcePathFile = m_source;
                    m_filesForProcessing.Add(file);
                }
                else
                {
                    foreach (string f in Directory.GetFiles(m_source, "*.dvr-ms", SearchOption.TopDirectoryOnly))
                    {
                        file = new FileForProcessing();
                        file.SourcePathFile = f;
                        m_filesForProcessing.Add(file);
                    }
                }
            }

            if (m_convertor == Convertor.DVRMSToolbox)
            {
                foreach (string f in Directory.GetFiles(m_source, "*.dvr-ms", SearchOption.TopDirectoryOnly))
                {
                    file = new FileForProcessing();
                    file.SourcePathFile = f;
                    m_filesForProcessing.Add(file);
                }
            }
        }

        private void processFiles()
        {
            try
            {
                for(int i = 0; i < m_filesForProcessing.Count; i++)
                {
                    //TODO:DS Split into functions
                    //TODO:DS Handle marking files as in process and complete/failed
                    FileForProcessing file = m_filesForProcessing.Item(i);
                    file.Status = ProcessingStatus.Processing;

                    grdFiles.Rows[i].Cells[0].Value = null;
                    grdFiles.Rows[i].Cells[0].Value = Properties.Resources.processing;
                    grdFiles.Refresh();
                    Thread.Sleep(50);
                    Application.DoEvents();

                    FileInfo f = new FileInfo(file.SourcePathFile);

                    if (file.MessageLog != null)
                        file.MessageLog.Clear();
                    else
                        file.MessageLog = new StringBuilder();
                    
                    file.MessageLog.AppendLine("Processing: " + f.Name);

                    string tvFilename = f.Name;
                    file.TVShowName = ReadDVRMSMetadata(file.SourcePathFile, "Title");
                    int tvSeason = Convert.ToInt32(tvFilename.Substring(1, tvFilename.IndexOf("E")-1));
                    int tvEpisode = Convert.ToInt32(tvFilename.Substring(tvFilename.IndexOf("E") + 1, tvFilename.IndexOf(" ") - tvFilename.IndexOf("E")-1));
                    string tvEpisodeName = tvFilename.Substring(tvFilename.IndexOf(" ") + 1);
                    tvEpisodeName = tvEpisodeName.Trim(new char[2] { ' ', '-' });
                    tvEpisodeName = tvEpisodeName.Replace(f.Extension, "");

                    file.MessageLog.AppendLine(string.Format("            {0}", file.TVShowName));
                    file.MessageLog.AppendLine(string.Format("            [Season {0}, Episode {1}] {2}", tvSeason, tvEpisode, tvEpisodeName));

                    string fileForProcessing = "";
                    string fileProcessed = "";
                    string fileForItunes = "";

                    if (m_convertor == Convertor.DVRMSToolbox)
                    {
                        fileProcessed = Path.Combine(m_destination, file.TVShowName, "Season " + tvSeason.ToString());
                        if (!Directory.Exists(fileProcessed)) Directory.CreateDirectory(fileProcessed);
                        fileProcessed = Path.Combine(fileProcessed, tvFilename.Substring(0, tvFilename.Length - f.Extension.Length) + ".mp4");

                        fileForItunes = Path.Combine(getiTunesLibraryLocation(), "iTunes Media", "Automatically Add to iTunes", tvFilename.Substring(0, tvFilename.Length - f.Extension.Length) + ".mp4");
                        Application.DoEvents();

//                        m_steps.SetStepComplete(StepName.Processing, "", false);
//                        m_steps.SetStepInProcess(StepName.Converting);

                        // TODO:DS Get the path of DVRMSToolbox from registry at:
                        // HKEY_CLASSES_ROOT\TypeLib\{B228D6B3-395D-47C2-814A-691DF8E414BA}\1.0\HELPDIR

                        // "D:\Films for Processing\Conversion\DVRMSToolbox\DVRMStoMPEG.exe" 
                        //      /if="D:\Films for Processing\Conversion\Pre Conversion\Little Princess\S02E16 - I Want My Puppets.dvr-ms"
                        //      /of="D:\Films for Processing\Conversion\Converted\Little Princess\Test.mp4"
                        //      /p=32 /act="Convert DVR-MS to MP4"
                        ProcessStartInfo info = new ProcessStartInfo();
                        info.FileName = "D:\\Films for Processing\\Conversion\\DVRMSToolbox\\DVRMStoMPEG.exe";
                        info.Arguments = string.Format("/if=\"{0}\" /of=\"{1}\" /p=32 /act=\"Convert DVR-MS to MP4\"",
                            file,
                            @fileProcessed);
                        info.UseShellExecute = false;
                        info.RedirectStandardOutput = true;
                        info.RedirectStandardError = false;
                        info.WindowStyle = ProcessWindowStyle.Hidden;
                        info.CreateNoWindow = true;

                        Process process = Process.Start(info);

                        TextReader stdOutput = process.StandardOutput;
                        string result = "";
                        string outputLine = "";

                        while (!process.HasExited)
                        {
                            outputLine = stdOutput.ReadLine() ?? "";
//                            m_steps.SetSubTitleText(StepName.Converting, outputLine);
                            result += outputLine;
                            result += "\r\n";
                        }

                        bool error = (process.ExitCode != 0 || !File.Exists(fileProcessed));

                        process.Close();

                        if (error)
                        {
                            if (File.Exists(fileProcessed)) File.Delete(fileProcessed);
                        }
                        else
                        {
                            File.Delete(file.SourcePathFile);
                        }

                        m_errorsOccurred = (m_errorsOccurred || error);

//                        m_steps.SetStepComplete(StepName.Converting, result, error);
                    }

                    if (m_convertor == Convertor.HandbrakeCLI)
                    {
//                        fileProcessed = Path.Combine(m_destination, file.TVShowName, "Season " + tvSeason.ToString());
                        fileProcessed = m_destination;
                        if (!Directory.Exists(fileProcessed)) Directory.CreateDirectory(fileProcessed);
                        fileProcessed = Path.Combine(fileProcessed, tvFilename.Substring(0, tvFilename.Length - f.Extension.Length) + ".m4v");

                        fileForItunes = Path.Combine(getiTunesLibraryLocation(), "iTunes Media", "Automatically Add to iTunes", tvFilename.Substring(0, tvFilename.Length - f.Extension.Length) + ".m4v");
                        Application.DoEvents();

                        bool error = false;

                        // TODO:DS Allow an option to overwrite existing output files
                        if (!File.Exists(fileProcessed))
                        {
                            file.MessageLog.AppendLine("Converting...");
                            m_Output = "";

                            //%HANDBRAKE% --input "%%i" --output "%%~ni.mp4" --size 500
                            m_process = new Process();
                            m_process.StartInfo.FileName = m_handbrakeOptions.ConvertorPath;
                            m_process.StartInfo.Arguments = string.Format("-i \"{0}\" -t 1 -c 1 -o \"{1}\" -f mp4 -4 -w 704 --loose-anamorphic -e x264 -q 20 -r 29.97 --pfr -a 1 -E faac -6 dpl2 -R Auto -B 160 -D 0.0",
                                file.SourcePathFile,
                                @fileProcessed);
                            m_process.StartInfo.UseShellExecute = false;
                            m_process.StartInfo.RedirectStandardOutput = true;
                            m_process.StartInfo.RedirectStandardError = true;
                            m_process.StartInfo.ErrorDialog = false;
                            m_process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                            m_process.StartInfo.CreateNoWindow = true;

                            m_process.ErrorDataReceived += new DataReceivedEventHandler(process_ErrorDataReceived);
                            m_process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
                            m_process.EnableRaisingEvents = true;

                            Trace.TraceInformation("EXEC: {0} {1}", m_process.StartInfo.FileName, m_process.StartInfo.Arguments);

                            m_process.Start();
                            m_process.BeginOutputReadLine();
                            m_process.BeginErrorReadLine();
                            //process.WaitForExit();
                            while (!m_process.HasExited)
                            {
                                Thread.Sleep(100); Application.DoEvents();
                            }


                            if (m_Output != "") file.MessageLog.AppendLine(m_Output);

                            m_process.ErrorDataReceived -= new DataReceivedEventHandler(process_ErrorDataReceived);
                            m_process.OutputDataReceived -= new DataReceivedEventHandler(process_OutputDataReceived);

                            error = (m_process.ExitCode != 0 || !File.Exists(fileProcessed));

                            m_process.Close();

                            if (error)
                                if (m_handbrakeOptions.DeleteDestinationOnError)
                                    if (File.Exists(fileProcessed))
                                        File.Delete(fileProcessed);
                                    else
                                        //        if (chklstOptions.GetItemChecked(
                                        //                            File.Delete(filePreProcessing);

                                        m_errorsOccurred = (m_errorsOccurred || error);

                            if (error)
                            {
                                file.MessageLog.AppendLine("Conversion Failed.");
                                file.Status = ProcessingStatus.CompleteFailed;
                                grdFiles.Rows[i].Cells[0].Value = null;
                                grdFiles.Rows[i].Cells[0].Value = Properties.Resources.invalid;
                            }
                            else
                            {
                                file.MessageLog.AppendLine("Conversion Complete.");
                                grdFiles.Rows[i].Cells[0].Value = null;
                                grdFiles.Rows[i].Cells[0].Value = Properties.Resources.ok;
                            }
                        }
                        else
                        {
                            file.MessageLog.AppendLine("Destination file already exists - skipping conversion.");
                            grdFiles.Rows[i].Cells[0].Value = null;
                            grdFiles.Rows[i].Cells[0].Value = Properties.Resources.invalid;
                        }

                        grdFiles.Refresh();
                    }

                    if (m_convertor == Convertor.MCEBuddy)
                    {
                        fileForProcessing = Path.Combine(getMCEBuddySourcePath(), tvFilename);
                        fileProcessed = Path.Combine(getMCEBuddyDestinationPath(), tvFilename.Substring(0, tvFilename.Length - f.Extension.Length) + ".mp4");
                        fileForItunes = Path.Combine(getiTunesLibraryLocation(), "iTunes Media", "Automatically Add to iTunes", tvFilename.Substring(0, tvFilename.Length - f.Extension.Length) + ".mp4");
                        Application.DoEvents();

                        // Stop the MCEBuddy service
                        StopService("MCEBuddy", 60000);
                        Application.DoEvents();

                        // Copy the file to the MCEBuddy Source folder
                        if (File.Exists(fileForProcessing)) File.Delete(fileForProcessing);
                        File.Copy(file.SourcePathFile, fileForProcessing);
                        Application.DoEvents();

                        // Delete the log so we can convert files that have already been converted!
                        // EXAMPLE Log:
                        // [ProcessedFiles]
                        // D:\Films for Processing\Conversion\To Convert\S02E17 - Mother's Day.dvr-ms=(29/10/2010 00:04) Converted to D:\Films for Processing\Conversion\Converted\S02E17 - Mother's Day.mp4
                        INIFile ini = new INIFile(Path.Combine(getMCEBuddyServicePath(), "filehistory.log"));
                        ini.DeleteValue("ProcessedFiles", Path.Combine(getMCEBuddySourcePath(), tvFilename).ToString());
                        ini = null;
                        Application.DoEvents();

                        // Restart the MCEBuddy service
                        if (RestartService("MCEBuddy", 60000) == false)
                            throw new Exception("Failed to restart the MCEBuddy service.");
                        Application.DoEvents();

//                        m_steps.SetStepComplete(StepName.Processing, "", false);
//                        m_steps.SetStepInProcess(StepName.Converting);

                        Thread.Sleep(5000);
                        Application.DoEvents();

                        // Now wait for the file to complete conversion
                        while (IsFileLocked(fileProcessed))
                        {
//                            m_steps.SetTitleText(StepName.Converting, "MCEBuddy is converting the file");
//                            m_steps.SetSubTitleText(StepName.Converting, getMCEBuddyCurrentActivity());
                            Thread.Sleep(500);
                            Application.DoEvents();
                        }

                        // Stop the MCEBuddy service
                        StopService("MCEBuddy", 60000);
                        Application.DoEvents();

//                        m_steps.SetStepComplete(StepName.Converting, "", false);
                    }

                    if (!m_errorsOccurred)
                    {
                        if (m_handbrakeOptions.AtomicParsley)
                        {
                            file.MessageLog.AppendLine("Adding iTunes Tags Using AtomicParsley...");

                            // Update the resulting file with metadata
                            runParsley(fileProcessed, file.TVShowName, tvEpisodeName, tvSeason, tvEpisode);
                        }

                        if (m_handbrakeOptions.CopyToiTunes)
                        {
                            file.MessageLog.AppendLine("Copying to iTunes Auto Add Folder...");

                            // Copy the file to iTunes auto import folder
                            if (File.Exists(fileForItunes)) File.Delete(fileForItunes);
                            File.Copy(fileProcessed, fileForItunes);
                        }
                        file.MessageLog.AppendLine("Finished.");

                        if (file.Status == ProcessingStatus.Processing) file.Status = ProcessingStatus.CompleteOK;

                        Thread.Sleep(600);
                        Application.DoEvents();
                    }
                    else
                    {
                        for (int s = 1; s < 100; s++)
                        {
                            Thread.Sleep(10);
                            Application.DoEvents();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            string strMessage = e.Data;

            if (toolstripProgress != null && strMessage != String.Empty)
            {
                // EXAMPLE outputLine: "Encoding: task 1 of 1, 88.60 % (351.54 fps, avg 351.86 fps, ETA 00h00m05s)"
                if (strMessage != null) strMessage = strMessage.Replace("task 1 of 1, ", "");
                staMain.BeginInvoke((ThreadStart)delegate() { toolstripProgress.Text = strMessage; staMain.Refresh(); });
            }
        }

        void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            string strMessage = e.Data;

            m_Output += (strMessage + "\r\n");
        }

        #endregion

        #region MCEBuddy

        private string getMCEBuddyServicePath()
        {
            try
            {
                return Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Tyrell\MCEBuddy", false).GetValue("ServicePath").ToString();
            }
            catch
            {
                return Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\Tyrell\MCEBuddy", false).GetValue("ServicePath").ToString();
            }
        }

        private string getMCEBuddySourcePath()
        {
            RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Tyrell\MCEBuddy", false);
            return key.GetValue("SourcePath").ToString();
        }

        private string getMCEBuddyDestinationPath()
        {
            RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Tyrell\MCEBuddy", false);
            return key.GetValue("DestinationPath").ToString();
        }

        private string getMCEBuddyCurrentActivity()
        {
            RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Tyrell\MCEBuddy", false);
            string value = key.GetValue("CurrentActivity").ToString();

            if (value.Contains("\r\n"))
                return value.Substring(0, value.IndexOf("\r\n") - 1);
            else
                return value;
        }

        public static bool RestartService(string serviceName, int timeoutMilliseconds)
        {
            ServiceController service = new ServiceController(serviceName);
            int millisec1 = Environment.TickCount;
            TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);

            try {
                service.Stop();
            }
            catch { }

            try {
                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
            }
            catch {
                return false;
            }

            // count the rest of the timeout
            int millisec2 = Environment.TickCount;
            timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2 - millisec1));

            try {
                service.Start();
            }
            catch {
                return false;
            }

            try
            {
                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
            }
            catch {
                return false;
            }

            return true;
        }

        public static bool StopService(string serviceName, int timeoutMilliseconds)
        {
            ServiceController service = new ServiceController(serviceName);
            int millisec1 = Environment.TickCount;
            TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);

            try
            {
                service.Stop();
            }
            catch { }

            try
            {
                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
            }
            catch
            {
                return false;
            }

            return true;
        }

        #endregion

        #region AtomicParsley

        private void runParsley(string mp4File, string tvShowName, string tvEpisodeName, int tvSeasonNum, int tvEpisodeNum)
        {
            // TODO:DS Add support for:
            //      --TVNetwork     ("Station name" from DVRMS files)
            //      --year          ("Year" from DVRMS files)
            //      --description   ("Program description" from DVRMS files)
            //      --compilation true
            //      --artwork
            // TODO:DS http://moviethumbnail.sourceforge.net/

            ProcessStartInfo info = new ProcessStartInfo();
            string genre = "TV Shows";
            string stik = "TV Show";

            info.FileName = "D:\\Films for Processing\\Conversion\\AtomicParsley\\AtomicParsley.exe";
            info.Arguments = string.Format(
                "\"{0}\" --title \"{2}\" --TVShowName \"{1}\" --TVEpisode \"{2}\" --TVSeasonNum \"{3}\" --TVEpisodeNum \"{4}\" --genre \"{5}\" --stik \"{6}\" --overWrite",
                mp4File,
                tvShowName,
                tvEpisodeName,
                tvSeasonNum,
                tvEpisodeNum,
                genre,
                stik);
            info.UseShellExecute = false;
            info.RedirectStandardOutput = true;
            info.WindowStyle = ProcessWindowStyle.Hidden;
            info.CreateNoWindow = true;

            Process process = Process.Start(info);

            string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();

            process.Close();

        }

        #endregion

        #region iTunes

        private string getiTunesLibraryLocation()
        {
            string iTunesPrefs = Path.Combine(Environment.GetEnvironmentVariable("AppData"), "Apple Computer", "iTunes", "iTunesPrefs.xml");

            XmlDocument doc = new XmlDocument();
            doc.Load(iTunesPrefs);
            XmlElement root = doc.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("//dict//dict[4]");
            XmlNodeList children = nodes[0].ChildNodes;

            foreach (XmlNode node in children)
            {
                if (node.InnerText == "iTunes Library Location:1")
                {
                    string path = DecodeBase64(node.NextSibling.InnerText);
                    return path;
                }
            }

            return "";
        }

        private string DecodeBase64(string encodedData)
        {
            byte[] encodedBytes = System.Convert.FromBase64String(encodedData);
            return System.Text.UnicodeEncoding.Unicode.GetString(encodedBytes);
        }

        #endregion
    }
}
